﻿using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Types;
using RayDen.RayEngine.Data;

namespace RayDen.RayEngine.VertexFramework
{
    public abstract class VertexPathSamplerBase : PathSamplerBase
    {
        protected static int VerticesMax = 20;
    }

    public enum GenericPathSamplerState
    {
        Initialize,
        Sampling,
        Connection,
        Evaluation,
    }

    public struct PathConnection
    {
        public RayData Ray;
        public RgbSpectrum Throughput;
        public float Pdf;
        public int PrimitiveIndex, currentShadowRayIndex;
    }

    public class GenericPathSampler : VertexPathSamplerBase
    {
        public PathElement[] vertices;
        public PathConnection[] connections;


        internal RgbSpectrum Throughput;
        public GenericPathSamplerState PathState;

        protected int depth, currentVertice, tracedShadowRayCount, indexRef, verticesCount;
        protected float pathWeight;
        protected bool specularBounce;

        protected internal RayEngineScene scene;

        public GenericPathSampler()
        {
            vertices = new PathElement[VerticesMax];
        }

        public int MaxRaysPerPath
        {
            get;
            set;
        }

        public override void InitPath(IPathProcessor buffer)
        {
            base.InitPath(buffer);
            this.scene = pathIntegrator.Scene;
            this.Radiance = new RgbSpectrum(0f);
            this.Throughput = new RgbSpectrum(1f);
            this.PathState = GenericPathSamplerState.Initialize;
            //vertices = new PathVertex[scene.MaxPathDepth * 2];
            this.Sample = pathIntegrator.Sampler.GetSample(null);
            IRay ray;
            pathIntegrator.Scene.Camera.GetRay(Sample.imageX, Sample.imageY, out ray);
            currentVertice = 0;
            vertices[currentVertice] = new ObserverPathElement() { CameraSample = new CameraSample() { EyeRay = (RayData)ray, imageX = (float)Sample.imageX, imageY = (float)Sample.imageY } };
            currentVertice++;
            this.PathRay = (RayData)ray;
            this.RayIndex = -1;
            this.pathWeight = 1.0f;
            this.depth = 0;
            this.verticesCount = 0;
            this.specularBounce = true;
        }

        public override bool FillRayBuffer(RayBuffer rayBuffer)
        {
            var leftSpace = rayBuffer.LeftSpace();
            if (((this.PathState == GenericPathSamplerState.Initialize) && (1 > leftSpace)) ||
                ((PathState == GenericPathSamplerState.Connection | PathState == GenericPathSamplerState.Evaluation) && (tracedShadowRayCount > leftSpace)) ||
            ((this.PathState == GenericPathSamplerState.Sampling) && (1 > leftSpace)))
                return false;
            if (PathState == GenericPathSamplerState.Evaluation || PathState == GenericPathSamplerState.Connection)
            {
                for (int i = 0; i < tracedShadowRayCount; ++i)
                    connections[i].currentShadowRayIndex = rayBuffer.AddRay(connections[i].Ray);
            }
            RayIndex = rayBuffer.AddRay(PathRay);
            return true;
        }
    }
}